#ifndef __GAME_BYTE_H__
#define __GAME_BYTE_H__


#include "game_config.h"
#include "game_def.h"
#include <vector>

#if CGAME_TARGET_PLATFORM == CGAME_PLATFORM_LINUX
#include <endian.h>
#elif CGAME_TARGET_PLATFORM == CGAME_PLATFORM_MAC
#include <machine/endian.h>
#endif


#include <stddef.h>



#define CGAME_BYTE_BUFF_MAX_LEN          8 * 1024

typedef UINT32 buff_size_t;
typedef UINT8 buff_t;
typedef UINT32 buff_pos_t;

size_t __writeBytes(BYTE* dest,const void* from,size_t pos,size_t size);
size_t __writeByte(BYTE* buf,size_t pos,BYTE v);
size_t __writeUINT8(BYTE* buf,size_t pos,UINT8 v);
size_t __writeUINT16(BYTE* buf,size_t pos,UINT16 v);
size_t __writeUINT32(BYTE* buf,size_t pos,UINT32 v);

size_t __writeUINT16_BE(BYTE* buf,size_t pos,UINT16 v);
size_t __writeUINT32_BE(BYTE* buf,size_t pos,UINT32 v);


size_t __writeINT8(BYTE* buf,size_t pos,INT8 v);
size_t __writeINT16(BYTE* buf,size_t pos,INT16 v);
size_t __writeINT32(BYTE* buf,size_t pos,INT32 v);

size_t __writeINT16_BE(BYTE* buf,size_t pos,INT16 v);
size_t __writeINT32_BE(BYTE* buf,size_t pos,INT32 v);


void __readBytes(void* dest,const BYTE* from,size_t pos,size_t size);
BYTE __readByte(const BYTE* buf,size_t pos);
UINT8 __readUINT8(const BYTE* buf,size_t pos);
UINT16 __readUINT16(const BYTE* buf,size_t pos);
UINT32 __readUINT32(const BYTE* buf,size_t pos);
INT8 __readINT8(const BYTE* buf,size_t pos);
INT16 __readINT16(const BYTE* buf,size_t pos);
INT32 __readINT32(const BYTE* buf,size_t pos);
void __readString(char* dest,const BYTE* from,size_t pos,size_t size);

UINT16 __readUINT16_BE(const BYTE* buf,size_t pos);
UINT32 __readUINT32_BE(const BYTE* buf,size_t pos);
INT16 __readINT16_BE(const BYTE* buf,size_t pos);
INT32 __readINT32_BE(const BYTE* buf,size_t pos);

BYTE __byte_from_hex(const char* ptr);
void __byte_to_hex(char* dest,const BYTE value);
void __bytes_from_hex(BYTE* dest, const char* value, size_t outSize);
void __bytes_to_hex(char* dest,const BYTE* value,size_t len);

class CGameLogger;

struct bytebuf_t{
  BYTE *_ptr;
  size_t _capacity;
};

class CGameByteArray{
public:
protected:
  int _endian = LITTLE_ENDIAN;

  /**
   * @brief 是否池化模式
   *
   */
  BOOL _pool = FALSE;

  size_t _capacity;
  BYTE *_ptr;
  size_t _position;
  size_t _size;
public:
  CGameByteArray();
  CGameByteArray(size_t capacity);
  CGameByteArray(BYTE *ptr,size_t size);
  CGameByteArray(bytebuf_t &buf);
  virtual ~CGameByteArray();
  void setEndian(int v);
  int getEndian() const;
  size_t getSize() const;
  size_t getCapacity() const;
  size_t getPosition() const;
  size_t setPosition(size_t pos);
  BOOL getPool() const;

  const BYTE *data() const;

  size_t readBytes(void *dest,size_t len);
  size_t readString(char *dest);

  UINT8 readUINT8();
  UINT16 readUINT16();
  UINT32 readUINT32();

  INT8 readINT8();
  INT16 readINT16();
  INT32 readINT32();

  BOOL writeUINT8(UINT8 v);
  BOOL writeUINT16(UINT16 v);
  BOOL writeUINT32(UINT32 v);

  BOOL writeINT8(INT8 v);
  BOOL writeINT16(INT16 v);
  BOOL writeINT32(INT32 v);


  size_t writeBytes(const void* src,size_t len);
  void writeBytez(BYTE v,size_t size);

  size_t writeString(const char *src);
  size_t writeString(const char *src,size_t len);

  void reset();
  void clear();

};

struct CGameByteStack_t{
  BYTE* _ptr;
  size_t _size;
};

class CGameByteStack{
private:
  std::vector<CGameByteStack_t*> _vec;
  std::vector<CGameByteStack_t*> _stack;
  size_t _capacity;
  size_t _size;
  size_t _num;
  BYTE* _ptr;
public:
  CGameByteStack(size_t size,size_t num);
  CGameByteStack_t* alloc();
  void dealloc(CGameByteStack_t* ctx);
  size_t getCapacity() const{
    return _capacity;
  }

  size_t getSize() const{
    return _size;
  }

  size_t getNum() const{
    return _num;
  }
};

class CGameByteBuffer
{
protected:
  buff_t _buff[CGAME_BYTE_BUFF_MAX_LEN];
  buff_size_t _offset;
  buff_size_t _size;
public:
  CGameByteBuffer();
  ~CGameByteBuffer();


  /**
   *@brief
   */
  const buff_t *data(void) const;

  /**
   *@brief 网络消息大小
   */
  buff_size_t size(void) const;

  buff_pos_t position() const;
  void position(buff_pos_t v);

  void writeBytes(const buff_t* buf,buff_size_t size);
  void writeBytez(BYTE v,buff_size_t size);
  void writeByte(BYTE byte);
  void writeUINT8(UINT8 v);
  void writeUINT16(UINT16 v);
  void writeUINT32(UINT32 v);

  void readString(char* dest,buff_size_t size);
  void readBytes(buff_t* dest,buff_size_t size);
  BYTE readByte();
  UINT8 readUINT8();
  UINT16 readUINT16();
  UINT32 readUINT32();

  static void print(CGameLogger *logger,const char* msg,buff_t *buf,buff_size_t len);
};

class CGameByteRing{
private:
  BYTE *_buf;
  UINT32 _read;
  UINT32 _write;
  UINT32 _capacity;
public:
  /**
   * @brief
   *
   */
  CGameByteRing(UINT32 capacity);
  ~CGameByteRing();

  UINT32 writeAvailable();
  BOOL write(const BYTE* src,UINT32 len);
  BOOL read(BYTE* dest,UINT32 len);
  UINT32 readAvailable();
  void reset();
  UINT32 getCapacity();
};



#endif
